#include"../include/ttfParser_Cell_ContentPointers.hpp"
#include<thread>



namespace LccStuffCollector{
namespace TTFParser{




// fileHead
TTFPARSER_API void fileHead::form(){
	if(!cover) return;
	if(!formPass) return;
	scaler_type  =cover->scaler_type;
	numTables    =&(cover->numTables);
	searchRange  =&(cover->searchRange);
	entrySelector=&(cover->entrySelector);
	rangeShift   =&(cover->rangeShift);
	if(!LccToolbox::endianlittle()) goto END;// ttf is big endian
	endianSwap(*numTables);
	endianSwap(*searchRange);
	endianSwap(*entrySelector);
	endianSwap(*rangeShift);
	END:
	formPass=false;
	formed=true;
}
TTFPARSER_API void fileHead::print(){
	if(!formed) return;
	printf("[headSign]\n\
              : %u%u%u%u\rscaler_type\n\
              : %u\rnumTables\n\
              : %u\rsearchRange\n\
              : %u\rentrySelector\n\
              : %u\rrangeShift\n",
		scaler_type[0],scaler_type[1],scaler_type[2],scaler_type[3],
		*numTables,
		*searchRange,
		*entrySelector,
		*rangeShift
	);
}




// tableTiemCover
TTFPARSER_API void tableItem::form(){
	if(!cover) return;
	if(!formPass) return;
	tag     =cover->tag;
	checkSum=&(cover->checkSum);
	offset  =&(cover->offset);
	length  =&(cover->length);
	if(!LccToolbox::endianlittle()) goto END;// ttf is big endian
	endianSwap(*checkSum);
	endianSwap(*offset);
	endianSwap(*length);
	END:
	formPass=false;
	formed=true;
}
TTFPARSER_API void tableItem::print(){
	if(!formed) return;
	printf("[table %c%c%c%c %p] - - - -\n\
         : %u\rcheckSum\n\
         : %u\roffset\n\
         : %u\rlength\n",
		tag[0],tag[1],tag[2],tag[3],
		((char*)center->filehead.cover)+*offset,
		*checkSum,
		*offset,
		*length
	);
}




TTFPARSER_API void nameTable::form(){
	if(!cover) return;
	if(!formPass) return;
	format      =&(cover->format);
	count       =&(cover->count);
	stringOffset=&(cover->stringOffset);
	nameRecord  =cover->nameRecord;
	name        =nameRecord+*count;
	if(!LccToolbox::endianlittle()) goto END;// ttf is big endian
	endianSwap(*format);
	endianSwap(*count);
	endianSwap(*stringOffset);
	for(uint16_t i=0;i<*count;++i)
	{	endianSwap(nameRecord[i].platformID);
		endianSwap(nameRecord[i].platformSpecificID);
		endianSwap(nameRecord[i].languageID);
		endianSwap(nameRecord[i].nameID);
		endianSwap(nameRecord[i].length);
		endianSwap(nameRecord[i].offset);
	}
	END:
	formPass=false;
	formed=true;
}
TTFPARSER_API void nameTable::print(){
	if(!formed) return;
	printf("[nameTable %p] - - - -\n\
            : %u\rformat\n\
            : %u\rcount\n\
            : %u\rstringOffset\n",
       	cover,
		*format,
		*count,
		*stringOffset
	);
	for(uint16_t i=0;i<*count;++i)
	{	printf("[NameRecords %u] - - - -\n\
                  : %u\rplatformID\n\
                  : %u\rplatformSpecificID\n\
                  : %u\rlanguageID\n\
                  : %u\rnameID\n\
                  : %u\rlength\n\
                  : %u\roffset\n",i,
			nameRecord[i].platformID,
			nameRecord[i].platformSpecificID,
			nameRecord[i].languageID,
			nameRecord[i].nameID,
			nameRecord[i].length,
			nameRecord[i].offset
		);
	}
	// names
}




// postTable // now needn't




// headTable
TTFPARSER_API void headTable::form(){
	if(!cover) return;
	if(!formPass) return;
	version           =&(cover->version);
	fontRevision      =&(cover->fontRevision);
	checkSumAdjustment=&(cover->checkSumAdjustment);
	magicNumber       =&(cover->magicNumber);
	flags             =&(cover->flags);
	unitsPerEm        =&(cover->unitsPerEm);
	created           =&(cover->created);
	modified          =&(cover->modified);
	xMin              =&(cover->xMin);
	yMin              =&(cover->yMin);
	xMax              =&(cover->xMax);
	yMax              =&(cover->yMax);
	macStyle          =&(cover->macStyle);
	lowestRecPPEM     =&(cover->lowestRecPPEM);
	fontDirectionHint =&(cover->fontDirectionHint);
	indexToLocFormat  =&(cover->indexToLocFormat);
	glyphDataFormat   =&(cover->glyphDataFormat);
	if(!LccToolbox::endianlittle()) goto END;// ttf is big endian
	endianSwap(*version);
	endianSwap(*fontRevision);
	endianSwap(*checkSumAdjustment);
	endianSwap(*magicNumber);
	endianSwap(*flags);
	endianSwap(*unitsPerEm);
	endianSwap(*created);
	endianSwap(*modified);
	endianSwap(*xMin);
	endianSwap(*yMin);
	endianSwap(*xMax);
	endianSwap(*yMax);
	endianSwap(*macStyle);
	endianSwap(*lowestRecPPEM);
	endianSwap(*fontDirectionHint);
	endianSwap(*indexToLocFormat);
	endianSwap(*glyphDataFormat);
	END:
	formPass=false;
	formed=true;
}
TTFPARSER_API void headTable::print(){
	if(!formed) return;
	printf("[headTable %p] - - - -\n\
                  : %x\rversion\n\
                  : %x\rfontRevision\n\
                  : %u\rcheckSumAdjustment\n\
                  : %u\rmagicNumber\n\
                  : %u\rflags\n\
                  : %u\runitsPerEm\n\
                  : %lld\rcreated\n\
                  : %lld\rmodified\n\
                  : %u\rxMin\n\
                  : %u\ryMin\n\
                  : %u\rxMax\n\
                  : %u\ryMax\n\
                  : %u\rmacStyle\n\
                  : %u\rlowestRecPPEM\n\
                  : %d\rfontDirectionHint\n\
                  : %d\rindexToLocFormat\n\
                  : %d\rglyphDataFormat\n",
        cover,
		*version,
		*fontRevision,
		*checkSumAdjustment,
		*magicNumber,
		*flags,
		*unitsPerEm,
		*created,
		*modified,
		*xMin,
		*yMin,
		*xMax,
		*yMax,
		*macStyle,
		*lowestRecPPEM,
		*fontDirectionHint,
		*indexToLocFormat,
		*glyphDataFormat
	);
}




// maxpTable
TTFPARSER_API void maxpTable::form(){
	if(!cover) return;
	if(!formPass) return;
	version              =&(cover->version);
	numGlyphs            =&(cover->numGlyphs);
	maxPoints            =&(cover->maxPoints);
	maxContours          =&(cover->maxContours);
	maxComponentPoints   =&(cover->maxComponentPoints);
	maxComponentContours =&(cover->maxComponentContours);
	maxZones             =&(cover->maxZones);
	maxTwilightPoints    =&(cover->maxTwilightPoints);
	maxStorage           =&(cover->maxStorage);
	maxFunctionDefs      =&(cover->maxFunctionDefs);
	maxInstructionDefs   =&(cover->maxInstructionDefs);
	maxStackElements     =&(cover->maxStackElements);
	maxSizeOfInstructions=&(cover->maxSizeOfInstructions);
	maxComponentElements =&(cover->maxComponentElements);
	maxComponentDepth    =&(cover->maxComponentDepth);
	if(!LccToolbox::endianlittle()) goto END;// ttf is big endian
	endianSwap(*version);
	endianSwap(*numGlyphs);
	endianSwap(*maxPoints);
	endianSwap(*maxContours);
	endianSwap(*maxComponentPoints);
	endianSwap(*maxComponentContours);
	endianSwap(*maxZones);
	endianSwap(*maxTwilightPoints);
	endianSwap(*maxStorage);
	endianSwap(*maxFunctionDefs);
	endianSwap(*maxInstructionDefs);
	endianSwap(*maxStackElements);
	endianSwap(*maxSizeOfInstructions);
	endianSwap(*maxComponentElements);
	endianSwap(*maxComponentDepth);
	END:
	formPass=false;
	formed=true;
}
TTFPARSER_API void maxpTable::print(){
	if(!formed) return;
	printf("[maxpTable %p] - - - -\n\
                     : %x\rversion\n\
                     : %u\rnumGlyphs\n\
                     : %u\rmaxPoints\n\
                     : %u\rmaxContours\n\
                     : %u\rmaxComponentPoints\n\
                     : %u\rmaxComponentContours\n\
                     : %u\rmaxZones\n\
                     : %u\rmaxTwilightPoints\n\
                     : %u\rmaxStorage\n\
                     : %u\rmaxFunctionDefs\n\
                     : %u\rmaxInstructionDefs\n\
                     : %u\rmaxStackElements\n\
                     : %u\rmaxSizeOfInstructions\n\
                     : %u\rmaxComponentElements\n\
                     : %u\rmaxComponentDepth\n",
		cover,
		*version,
		*numGlyphs,
		*maxPoints,
		*maxContours,
		*maxComponentPoints,
		*maxComponentContours,
		*maxZones,
		*maxTwilightPoints,
		*maxStorage,
		*maxFunctionDefs,
		*maxInstructionDefs,
		*maxStackElements,
		*maxSizeOfInstructions,
		*maxComponentElements,
		*maxComponentDepth
	);
}




// cmapTable
TTFPARSER_API void cmapTable::form(){
	if(!cover) return;
	if(!formPass) return;
	version        =&(cover->version);
	numberSubtables=&(cover->numberSubtables);
	subTable       =cover->subTable;
	if(!LccToolbox::endianlittle()) goto END;// ttf is big endian
	endianSwap(*version);
	endianSwap(*numberSubtables);
	for(uint16_t i=0;i<*numberSubtables;++i)
	{	endianSwap(subTable[i].platformID);
		endianSwap(subTable[i].platformSpecificID);
		endianSwap(subTable[i].offset);
	}
	END:
	formPass=false;
	formed=true;
}
TTFPARSER_API void cmapTable::print(){
	if(!formed) return;
	printf("[cmapTable %p]\n\
               : %u\rversion\n\
               : %u\rnumberSubtables\n",
		cover,
		*version,
		*numberSubtables
	);
	for(uint16_t i=0;i<*numberSubtables;++i)
	{	printf("[subTable %u] - - - -\n\
                  : %u\rplatformID\n\
                  : %u\rplatformSpecificID\n\
                  : %u\roffset\n",
			i+1,
			subTable[i].platformID,
			subTable[i].platformSpecificID,
			subTable[i].offset
		);
	}
}




TTFPARSER_API void cmapSubTable::form(){
	if(!cover) return;
	if(!formPass) return;
	format  =&(cover->format);endianSwap(*format);
	length  =&(cover->length);
	language=&(cover->language);
	uint16_t* left=language+1;
	switch(*format)
	{	case 2:
		f2.subHeaderKeys=cover->f2.subHeaderKeys;
		f2.subHeaders   =cover->f2.subHeaders;
		break;
		case 4:
		f4.segCountX2     =&(cover->f4.segCountX2);endianSwap(*(f4.segCountX2));
		f4.searchRange    =&(cover->f4.searchRange);
		f4.entrySelector  =&(cover->f4.entrySelector);
		f4.rangeShift     =&(cover->f4.rangeShift);
		f4.endCode        =cover->f4.endCode;
		f4.reservedPad    =f4.endCode+*(f4.segCountX2)/2;
		f4.startCode      =f4.reservedPad+1;
		f4.idDelta        =reinterpret_cast<int16_t*>(f4.startCode+*(f4.segCountX2)/2);
		f4.idRangeOffset  =reinterpret_cast<uint16_t*>(f4.idDelta+*(f4.segCountX2)/2);
		f4.glyphIndexArray=f4.idRangeOffset+*(f4.segCountX2)/2;;
		endianSwap(*(f4.segCountX2));// avoid repeat swap
		break;
	}
	if(!LccToolbox::endianlittle()) goto END;// ttf is big endian
	endianSwap(*length);
	endianSwap(*language);
	for(uint16_t i=0;i<*length-6;++i)
		endianSwap(*left++);
	END:
	formPass=false;
	formed=true;
}




// locaTable
TTFPARSER_API void locaTable::form(){
	if(!cover) return;
	if(!formPass) return;
	offsets=cover->offsets_16;
	if(!LccToolbox::endianlittle()) goto END;// ttf is big endian
	if(*(center->head.indexToLocFormat))
	{	for(int i=int(*(center->maxp.numGlyphs)-1);i>=0;--i)
		{	endianSwap(offsets_32[i]);
		}
	}else
	{	for(int i=int(*(center->maxp.numGlyphs)-1);i>=0;--i)
		{	endianSwap(offsets_16[i]);
		}
	}
	END:
	formPass=false;
	formed=true;
}




TTFPARSER_API void glyfItem::form(){
	if(!cover) return;
	if(!formPass) return;
	numberOfContours=&(cover->numberOfContours);if(LccToolbox::endianlittle()) endianSwap(*numberOfContours); is_simple=(*numberOfContours)>=0;
	// printf("[[%d]]\n",*numberOfContours);
	xMin            =&(cover->xMin);
	yMin            =&(cover->yMin);
	xMax            =&(cover->xMax);
	yMax            =&(cover->yMax);
	// printf("|%d|\n",*xMin);
	// printf("|%d|\n",*yMin);
	// printf("|%d|\n",*xMax);
	// printf("|%d|\n",*yMax);
	if(is_simple)// simple
	{	simple.endPtsOfContours =cover->simple.endPtsOfContours;
		simple.instructionLength=simple.endPtsOfContours+*numberOfContours;
		simple.instructions     =reinterpret_cast<uint8_t*>((uint8_t*)(simple.instructionLength+1));
		simple.dataPacket       =simple.instructions+*(simple.instructionLength);
	}
	else component.dataPacket=(uint8_t*)(yMax+1);// component
	if(!LccToolbox::endianlittle()) goto END;// ttf is big endian
	endianSwap(*xMin);
	endianSwap(*yMin);
	endianSwap(*xMax);
	endianSwap(*yMax);
	if(is_simple)
	{	for(uint16_t i=0;i<*numberOfContours;++i)
		{	endianSwap(simple.endPtsOfContours[i]);
			// printf("%u;",simple.endPtsOfContours[i]);
		}
		endianSwap(*(simple.instructionLength));
		// instruction is 8bit, no need swap
		// packet swap in readFunc
		// {points read ready}
		auto& contours=simple.contours;
		contours.alloc(*numberOfContours);
		uint16_t pre=0;
		uint8_t* flag_p=simple.dataPacket;
		uint8_t stay=0;
		size_t strideOFx=0;// record the byte length of xCoord
		for(int16_t i=0;i<*numberOfContours;++i)// set each contours's each point's flag
		{	contours[i]._points.alloc(simple.endPtsOfContours[i]+1-pre);
			contours[i]._flags.alloc(simple.endPtsOfContours[i]+1-pre);
			for(size_t j=0;j<contours[i]._flags.size();++j)
			{	contours[i]._flags[j]=*flag_p;
				if((*flag_p)&flag_simple::x_Short_Vector) ++strideOFx;
				else if(!((*flag_p)&flag_simple::This_x_is_same)) strideOFx+=2;
				if(!stay)
				{	if((*flag_p)&flag_simple::Repeat) stay=*(flag_p+1);
					else ++flag_p;
				}
				else
					if(!--stay) ++flag_p;
			}
			pre=simple.endPtsOfContours[i]+1;
		}
		// points read
		uint8_t* x=flag_p;
		uint8_t* y=x+strideOFx;
		int32_t prepos[2]{0,0};
		pre=0;
		for(int16_t i=0;i<*numberOfContours;++i)// set each contours's each point's coord
		{	for(size_t j=0;j<contours[i]._points.size();++j)
			{	// sign short
				if(contours[i]._flags[j]&flag_simple::x_Short_Vector)
					prepos[0]+=(*x++)*((contours[i]._flags[j]&flag_simple::This_x_is_same)?1:-1);
				// long & !same
				else if(!(contours[i]._flags[j]&flag_simple::This_x_is_same))
				{	endianSwap(*reinterpret_cast<int16_t*>(x));
					prepos[0]+=*reinterpret_cast<int16_t*>(x);x+=2;
				}
				contours[i]._points[j].x=prepos[0];
				// Y case
				// sign short
				if(contours[i]._flags[j]&flag_simple::y_Short_Vector)
					prepos[1]+=(*y++)*((contours[i]._flags[j]&flag_simple::This_y_is_same)?1:-1);
				// long & !same
				else if(!(contours[i]._flags[j]&flag_simple::This_y_is_same))
				{	endianSwap(*reinterpret_cast<int16_t*>(y));
					prepos[1]+=*reinterpret_cast<int16_t*>(y);y+=2;
				}
				contours[i]._points[j].y=prepos[1];
			}
			pre=simple.endPtsOfContours[i];
		}
	}
	else// component
	{	uint8_t* dataPacket_p=component.dataPacket;
		auto& glyphs=component.glyphs;
		size_t i=0;
		MORE:
		glyphs.grow(1);i=glyphs.size()-1;
		glyphs[i].flag=endianSwap(*reinterpret_cast<uint16_t*>(dataPacket_p));  dataPacket_p+=2;
		glyphs[i].index=endianSwap(*reinterpret_cast<uint16_t*>(dataPacket_p)); dataPacket_p+=2;
		if(glyphs[i].flag&flag_component::ARG_1_AND_2_ARE_WORDS)
		{	if(glyphs[i].flag&flag_component::ARGS_ARE_XY_VALUES)
			{	glyphs[i].argument[0]=(int32_t)endianSwap(*reinterpret_cast<int16_t*>(dataPacket_p));dataPacket_p+=2;
				glyphs[i].argument[1]=(int32_t)endianSwap(*reinterpret_cast<int16_t*>(dataPacket_p));dataPacket_p+=2;
			}else
			{	glyphs[i].argument[0]=(int32_t)endianSwap(*reinterpret_cast<uint16_t*>(dataPacket_p));dataPacket_p+=2;
				glyphs[i].argument[1]=(int32_t)endianSwap(*reinterpret_cast<uint16_t*>(dataPacket_p));dataPacket_p+=2;
			}
		}else
		{	if(glyphs[i].flag&flag_component::ARGS_ARE_XY_VALUES)
			{	glyphs[i].argument[0]=(int32_t)(*reinterpret_cast<int8_t*>(dataPacket_p));++dataPacket_p;
				glyphs[i].argument[1]=(int32_t)(*reinterpret_cast<int8_t*>(dataPacket_p));++dataPacket_p;
			}else
			{	glyphs[i].argument[0]=(int32_t)(*reinterpret_cast<uint8_t*>(dataPacket_p));++dataPacket_p;
				glyphs[i].argument[1]=(int32_t)(*reinterpret_cast<uint8_t*>(dataPacket_p));++dataPacket_p;
			}
		}
		// scale case
		if(glyphs[i].flag&flag_component::WE_HAVE_A_SCALE)
		{	glyphs[i].scale.alloc(1);
			glyphs[i].scale[0]=endianSwap(*reinterpret_cast<int16_t*>(dataPacket_p));dataPacket_p+=2;
		}else if(glyphs[i].flag&flag_component::WE_HAVE_AN_X_AND_Y_SCALE)
		{	glyphs[i].scale.alloc(2);
			glyphs[i].scale[0]=endianSwap(*reinterpret_cast<int16_t*>(dataPacket_p));dataPacket_p+=2;
			glyphs[i].scale[1]=endianSwap(*reinterpret_cast<int16_t*>(dataPacket_p));dataPacket_p+=2;
		}else if(glyphs[i].flag&flag_component::WE_HAVE_A_TWO_BY_TWO)
		{	glyphs[i].scale.alloc(4);
			glyphs[i].scale[0]=endianSwap(*reinterpret_cast<int16_t*>(dataPacket_p));dataPacket_p+=2;
			glyphs[i].scale[1]=endianSwap(*reinterpret_cast<int16_t*>(dataPacket_p));dataPacket_p+=2;
			glyphs[i].scale[2]=endianSwap(*reinterpret_cast<int16_t*>(dataPacket_p));dataPacket_p+=2;
			glyphs[i].scale[3]=endianSwap(*reinterpret_cast<int16_t*>(dataPacket_p));dataPacket_p+=2;
		}
		if(glyphs[i].flag&flag_component::MORE_COMPONENTS) goto MORE;
	}
	END:
	formPass=false;
	formed=true;
}




#define takeCover(tgt,p) tgt.cover=reinterpret_cast<decltype(tgt.cover)>(p);
#define FormLine(ITEM) ITEM.center=this;_##ITEM=#ITEM;takeCover(ITEM,no_1+*(tableitems[tableIndexs.find(_##ITEM)->index()-1].offset));ITEM.form()
TTFPARSER_API void ttfReader::formAt(void*src){
	char*no_1=(char*)src;
	filehead.center=this;
	takeCover(filehead,src);
	filehead.form();

	char tableCall[5];tableCall[4]=0;
	tableitems.alloc(*(filehead.numTables));
	for(size_t i=0;i<tableitems.size();++i)
	{	tableitems[i].center=this;
		takeCover(tableitems[i],no_1+sizeof(fileHeadCover)+sizeof(tableItemCover)*i);
		tableitems[i].form();

		for(int j=0;j<4;++j) tableCall[j]=tableitems[i].tag[j];
		tableIndexs.insert(LccToolbox::mark{tableCall});
	}

	std::thread namepiece([&]{FormLine(name);});
	std::thread headpiece([&]{FormLine(head);});
	std::thread maxppiece([&]{FormLine(maxp);});
	std::thread cmappiece([&]{FormLine(cmap);});
	_glyf="glyf";tableIndexs.find(_glyf);
	headpiece.join();
	maxppiece.join();
	std::thread locapiece([&]{FormLine(loca);});
	namepiece.join();
	cmappiece.join();
	locapiece.join();
}
TTFPARSER_API void ttfReader::print(){
	printf("[%p]\n",filehead.cover);
	filehead.print();
	for(size_t i=0;i<tableitems.size();++i) tableitems[i].print();
	name.print();
	head.print();
	maxp.print();
	cmap.print();
	loca.print();
}




}// namespace TTFParser
}// namespace LccStuffCollector